﻿/*
Wrtiten by Webmaster442 (c) 2009
Uses The ICSharpCode.SharpZLib zip compression module
This is free software. License: GPL V2
*/
using System;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using System.Collections.Generic;

namespace Appcompact
{
    class arguments
    {
        public string srcdir;
        public byte level;
        public string outputpath;
        public string passwd;
        public static arguments Parse(string[] args)
        {
            arguments ret = new arguments();
            for (int i = 0; i < args.Length; i++)
            {
                switch (args[i])
                {
                    case "-src":
                        ret.srcdir = args[i + 1];
                        break;
                    case "-level":
                        ret.level = Convert.ToByte(args[i + 1]);
                        break;
                    case "-pass":
                        ret.passwd = args[i + 1];
                        break;
                    case "-out":
                        ret.outputpath = args[i + 1];
                        break;
                }
            }
            return ret;
        }
        public static bool isnull(arguments a)
        {
            if (string.IsNullOrEmpty(a.outputpath) || string.IsNullOrEmpty(a.srcdir)) return true;
            else return false;
        }

    }

    class Program
    {
        static void Help()
        {
            Console.WriteLine("Appcompact v. " + typeof(Program).Assembly.GetName().Version.ToString(3));
            Console.WriteLine("Usage: appcompact -src <source> -level <level> -out <output> -pass <passwd>");
            Console.WriteLine("   -src:    Sets the source directory");
            Console.WriteLine("   -out:    The output program name");
            Console.WriteLine("   -level:  Sets compression level (1-10) (optional parameter)");
            Console.WriteLine("   -pass:   Sets password for encription (optional parameter)");
            Console.WriteLine("If no level is specified the default is 6");
        }

        public static string[] GetAllFileNames(string baseDir, string mask)
        {
            List<string> fileResults = new List<string>();
            Stack<string> directoryStack = new Stack<string>();
            directoryStack.Push(baseDir);
            while (directoryStack.Count > 0 && fileResults.Count < 1000)
            {
                string currentDir = directoryStack.Pop();
                foreach (string fileName in Directory.GetFiles(currentDir, mask))
                {
                    fileResults.Add(fileName);
                }
                foreach (string directoryName in Directory.GetDirectories(currentDir))
                {
                    directoryStack.Push(directoryName);
                }
            }
            return fileResults.ToArray();
        }

        public static void Copy(Stream input, Stream output)
        {
            int cpy;
            byte[] buffer = new byte[4096];
            do
            {
                cpy = input.Read(buffer, 0, buffer.Length);
                output.Write(buffer, 0, cpy);
            }
            while (cpy > 0);
            output.Flush();
        }

        static void Main(string[] args)
        {
            try
            {
                arguments r = arguments.Parse(args);
                string[] filenames = GetAllFileNames(r.srcdir, "*.*");
                if (arguments.isnull(r)) Program.Help();
                else
                {
                    if (r.level == 0) r.level = 6;
                    if (r.level > 9) r.level = 9;
                    FileStream outp = File.Create(r.outputpath);
                    MemoryStream c = new MemoryStream();
                    outp.Write(Properties.Resources.loader, 0, Properties.Resources.loader.Length);
                    ZipOutputStream s = new ZipOutputStream(c);
                    s.SetLevel(r.level);
                     s.Password = r.passwd;

                    string dname, fname;
                    ZipEntry entry;

                    foreach (string file in filenames)
                    {
                        dname = Path.GetDirectoryName(file);
                        dname = dname.Replace(r.srcdir, "");
                        fname = Path.GetFileName(file);
                        entry = new ZipEntry(dname + @"\" + fname);
                        entry.DateTime = DateTime.Now;
                        if (!string.IsNullOrEmpty(r.passwd)) entry.IsCrypted = true;
                        s.PutNextEntry(entry);
                        Console.WriteLine("Compressing: " + dname + @"\" + fname);
                        using (FileStream fs = File.OpenRead(file))
                        {
                            Copy(fs, s);
                        }
                    }
                    s.Finish();
                    c.Seek(0, SeekOrigin.Begin);
                    Copy(c, outp);
                    outp.Close();
                    s.Close();
                    c.Close();
                }
            }
            catch
            {
                Program.Help();
            }
        }
    }
}
